package cn.base.web.lock;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 单机锁id实现
 * ReentrantLock 不支持锁id，使用synchronized实现
 */
@Slf4j
@Component
public class LocalLock implements LockService{
    //private final ReentrantLock lock = new ReentrantLock();
    private static final Map<String, Object> locks=new ConcurrentHashMap<>();
    /**
     * 第一种策略：用完即删
     * 第二种策略：存储指定个数，达到上限删除不常使用，可使用ConcurrentLruCache实现
     * **/
    // 用完后，如果直接删除id锁，那如果此时id锁已被使用，同步会失效， 判断是否还有ID的锁在用
    private static final Map<String, AtomicInteger> waitingLocks = new ConcurrentHashMap<>();//用完即删

    @Override
    public <T> T lock(String key, Callable<T> valueLoader) throws Exception {
        Object lock;
        AtomicInteger waitLock;
        synchronized(locks){
            lock=locks.computeIfAbsent(key, k -> new Object());
            waitLock=waitingLocks.computeIfAbsent(key, j -> new AtomicInteger());
            waitLock.incrementAndGet();//加1
        }

        T t;

        try {
            synchronized(lock){
                t=valueLoader.call();
            }
        } catch (Exception e) {
            throw e;
        }finally {
            synchronized(locks){
                if(waitLock.decrementAndGet() == 0){//减1
                    locks.remove(key);
                    waitingLocks.remove(key);
                }
            }
        }
        return t;
    }

    public static void main(String[] args) {
        AtomicInteger i=new AtomicInteger();
        System.out.println(i.get());
        int v=i.incrementAndGet();
        System.out.println(v);
    }
}
